#ifndef _BONUSBINGOCONSTANTS_H_
#define _BONUSBINGOCONSTANTS_H_

namespace BonusBingo
{
    enum WinPatterns
    {
        SLASH,
        BACKSLASH,
        CORNERS,
        TWO_LINES_HORIZ,
        CROSS,
        T_PATTERN,
        THREE_LINES_HORIZ,
        PERIMETER,
        FOUR_LINES_HORIZ,
        BINGO,        
        WIN_PATTERN_COUNT,
        LOSER
    };

    enum Constants
    {         
        NUM_CARD_COLS       =   5,
        NUM_CARD_ROWS       =   5,
        NUM_MAX_CARDS       =   4,
		NUM_BET_VALUES		=	5,
        NUM_BALLS_CHOSEN    =   44,   
        NUM_BALLS_TOTAL     =   75,
        PICK_RANGE_LOW      =   1,
        PICK_RANGE_HIGH     =   75,
        BONUS_ROUND_JOKERS_NEEDED = 5,
        NUMBER_OF_PICKS     =   25,
    };
    

    enum Payouts
    {
        SLASH_PAYOUT                =   1,
        BACKSLASH_PAYOUT            =   1,
        CORNERS_PAYOUT              =   2,
        TWO_LINES_HORIZ_PAYOUT      =   4,
        CROSS_PAYOUT                =   8,
        T_PATTERN_PAYOUT            =   10,
        THREE_LINES_HORIZ_PAYOUT    =   40,
        PERIMETER_PAYOUT            =   250,
        FOUR_LINES_HORIZ_PAYOUT     =   500,
        BINGO_PAYOUT                =   3000
    };

    enum SubGameDataEnums
    {
        BBSGIDX_STARTED,            
        BBSGIDX_NUM_JOKERBALLS,
        BBSGIDX_AVG_JOKER_BET,
        BBSGIDX_NUM_ROLLS_TOTAL,
        BBSGIDX_CURRENT_ROLL, 
        BBSGIDX_LAST_ROLL_CREDITS_WON,
        BBSGIDX_NUM_ROLLS_USED,
        BBSGIDX_TOTAL_CREDITS_WON,
        BBSGIDX_DIE_VALUE_1,
        BBSGIDX_DIE_VALUE_2,
        BBSGIDX_DIE_VALUE_3,
        BBSGIDX_DIE_VALUE_4,
        BBSGIDX_DIE_VALUE_5,
        BBSGIDX_DIE_VALUE_6,       
        BBSGIDX_DIE_VALUES = BBSGIDX_DIE_VALUE_1,
        BBSGIDX_COUNT = BBSGIDX_DIE_VALUE_6
    };

#define INDEX(__c, __r) (__r*5+__c)
#define HIT_AT(__c, __r) (0x1 << (BonusBingo::NUMBER_OF_PICKS - INDEX(__c, __r) - 1))
    
    //A HitMask is a bit set where a value of 1 on a bit means
    //the corresponding cell on the card was matched against
    //the drawn balls.
    //The pattern of bits is BINGOBINGOBINGOBINGOBINGO
    typedef int32 HitMask;

    //These are the "static" hit masks, meaning they match fixed
    //patterns on the card
    enum HitMasks
    {
        SlashHitMask        = HIT_AT(4, 0) | HIT_AT(3, 1) | HIT_AT(2, 2)
                            | HIT_AT(1, 3) | HIT_AT(0, 4),
        
        BackSlashHitMask    = HIT_AT(0, 0) | HIT_AT(1, 1) | HIT_AT(2, 2)
                            | HIT_AT(3, 3) | HIT_AT(4, 4),
        
        CornersHitMask      = HIT_AT(0, 0) | HIT_AT(0, 4) | HIT_AT(2, 2)
                            | HIT_AT(4, 0) | HIT_AT(4, 4),
        
        CrossHitMask        = SlashHitMask | BackSlashHitMask,
        
        TPatternHitMask     = HIT_AT(0, 0) | HIT_AT(1, 0) | HIT_AT(2, 0)
                            | HIT_AT(3, 0) | HIT_AT(4, 0) | HIT_AT(2, 1)
                            | HIT_AT(2, 2) | HIT_AT(2, 3) | HIT_AT(2, 4),
        
        PerimeterHitMask    = HIT_AT(0, 0) | HIT_AT(0, 1) | HIT_AT(0, 2)
                            | HIT_AT(0, 3) | HIT_AT(0, 4) | HIT_AT(1, 0)
                            | HIT_AT(1, 4) | HIT_AT(2, 0) | HIT_AT(2, 2)
                            | HIT_AT(2, 4) | HIT_AT(3, 0) | HIT_AT(3, 4)
                            | HIT_AT(4, 0) | HIT_AT(4, 1) | HIT_AT(4, 2)
                            | HIT_AT(4, 3) | HIT_AT(4, 4),
        
        BingoHitMask        = PerimeterHitMask | HIT_AT(1, 1) | HIT_AT(1, 3)
                            | HIT_AT(3, 1) | HIT_AT(3, 3),

		// Make sure the single 'row' hitmasks always include the center square like the others do,
		// so that overlap matching will work correctly.  FB 17664
        RowOneHitMask       = HIT_AT(0,0) | HIT_AT(1,0) | HIT_AT(2,0) | HIT_AT(3,0) | HIT_AT(4,0) | HIT_AT(2, 2),
        RowTwoHitMask       = HIT_AT(0,1) | HIT_AT(1,1) | HIT_AT(2,1) | HIT_AT(3,1) | HIT_AT(4,1) | HIT_AT(2, 2),
        RowThreeHitMask     = HIT_AT(0,2) | HIT_AT(1,2) | HIT_AT(2,2) | HIT_AT(3,2) | HIT_AT(4,2) | HIT_AT(2, 2),
        RowFourHitMask      = HIT_AT(0,3) | HIT_AT(1,3) | HIT_AT(2,3) | HIT_AT(3,3) | HIT_AT(4,3) | HIT_AT(2, 2),
        RowFiveHitMask      = HIT_AT(0,4) | HIT_AT(1,4) | HIT_AT(2,4) | HIT_AT(3,4) | HIT_AT(4,4) | HIT_AT(2, 2),

        //Used to tell hit-mask code
        //that it needs to use a line
        //evaluator instead of a static mask
        MultiLineMask       = RowOneHitMask << NUM_CARD_ROWS,

        TwoRowsHitMask      = MultiLineMask | 2,

        ThreeRowsHitMask    = MultiLineMask | 3,

        FourRowsHitMask     = MultiLineMask | 4
    };

    inline bool8 isStaticHitMask(HitMask hitMask)
    {
        return (hitMask & MultiLineMask) != MultiLineMask;
    }

    inline int32 getLinesNeeded(HitMask multiRowHitMask)
    {
        ASSERT( !isStaticHitMask( multiRowHitMask ) );

        return multiRowHitMask & ~MultiLineMask;
    }

    //Helper function to return the hit mask for a particular row
    inline HitMask getRowHitMask( int32 row )
    {
        // kharmon.  03-30-07.  The RowOneHitMask includes a bit for the center
        // square.  So we can't just shift it to the right, because the center square
        // bit shifts to, and ends up checking for hits on rows below the center row.
        // SO, here we turn OFF the center bit first, then do the shift, then turn the 
        // center bit back on, so that it's still in the center.  Otherwise the players
        // won't get some payouts.
        return  (((RowOneHitMask & ~(HIT_AT(2, 2))) >> (row * 5)) | HIT_AT(2, 2));
    }

    bool8 evaluateHitMask( HitMask& hitMask, HitMask testMask );

    inline bool8 evaluateHorizontalLines( HitMask& hitMask, HitMask testMask )
    {
        int winsNeeded = getLinesNeeded(testMask);

		HitMask copy;

        HitMask temp = 0;
        
        HitMask rowMask = 0;

        int row = 0;

        do
        {
            rowMask = getRowHitMask( row );            

			copy = hitMask;
            
            if ( ! evaluateHitMask( copy, rowMask ) )    //Row is a loser
            {
                continue;
            }
            else
            {
                //Remember that this row was a winner
                temp |= rowMask;
                winsNeeded--;
            }
            
            if ( !winsNeeded )
            {
                //Explain to the caller exactly where they won.
                hitMask = temp;
                return true;
            }
        }
        while ( ++row < NUM_CARD_ROWS );
        
        return false;
    }

    inline bool8 evaluateHitMask( HitMask& hitMask, HitMask testMask )
    {
        if ( isStaticHitMask(testMask) )
        {
            if ( (hitMask & testMask) == testMask )
            {
                hitMask = testMask;
                return true;
            }
        }
        else
        {
            return evaluateHorizontalLines( hitMask, testMask );
        }
        return false;
    }
}

#endif  //_BONUSBINGOCONSTANTS_H_